package com.pactera.asmp.server.common.logprint.utils;

import com.pactera.asmp.server.common.constants.MagicNumberConstant;
import com.pactera.asmp.server.common.logprint.bean.InterpretBean;
import com.pactera.asmp.server.common.logprint.bean.LogBean;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

public final class LogQueue {

    private final String TAG = "LogQueue:";
    /**
     * The constant LEFT_CURVES.
     */
    private static final String LEFT_CURVES = "(";
    /**
     * The constant RIGHT_CURVES.
     */
    private static final String RIGHT_CURVES = ")";

    /**
     * The constant LEFT_BRACKETS.
     */
    private static final String LEFT_BRACKETS = "[";
    /**
     * The constant RIGHT_BRACKETS.
     */
    private static final String RIGHT_BRACKETS = "]";

    /**
     * The constant TIME_STRING.
     */
    private static final String TIME_STRING = "time:";
    /**
     * The constant COMMA.
     */
    private static final String COMMA = ",";


    /**
     * The constant METHOD_NAME.
     */
    private static final String METHOD_NAME = "___serialize";

    /**
     * The constant LOG_DATE_FORMAT.
     */
    private static final String LOG_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
    /**
     * The constant sLogQueue.
     */
    private static volatile LogQueue sLogQueue;
    /**
     * The M blocking queue.
     */
    private LinkedBlockingQueue<LogBean> mBlockingQueue;

    /**
     * Instantiates a new Log queue.
     */
    private LogQueue() {
        mBlockingQueue = new LinkedBlockingQueue<LogBean>(Integer.MAX_VALUE);
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    LogBean logBean = null;
                    try {
                        logBean = mBlockingQueue.take();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.e(TAG,e.toString());
                    }
                    printLog(logBean);
                }
            }
        }).start();
    }

    /**
     * Print log.
     *
     * @param logBean the log bean
     */
    public static void printLog(LogBean logBean){
        Object[] datas = logBean.getData();
        StringBuffer stringBuffer = new StringBuffer(LEFT_CURVES);
        for (int i = MagicNumberConstant.ZERO; i < datas.length; i = MathUtil.safeAddOne(i)) {
            stringBuffer.append(toParamValue(datas[i]));
            if (i < MathUtil.safeSubtractOne(datas.length)) {
                stringBuffer.append(StringUtils.SPACE);
                stringBuffer.append(COMMA);
                stringBuffer.append(StringUtils.SPACE);
            }
        }
        stringBuffer.append(RIGHT_CURVES);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(LOG_DATE_FORMAT);
        LogUtil.i(StringUtils.LEFT,
                simpleDateFormat.format(new Date(logBean.getTime())),
                StringUtils.RIGHT,
                StringUtils.PREFIX,
                logBean.getTag(),
                StringUtils.SPACE,
                logBean.getClassName(),
                StringUtils.SPACE,
                logBean.getMethodName(),
                StringUtils.SPACE,
                stringBuffer.toString(),
                StringUtils.SPACE);
    }

    /**
     * Print Request Paramter
     * @param tag
     * @param list
     */
    public static void printRequestParamter(String tag, List<InterpretBean> list) {
        StringBuffer stringBuffer = new StringBuffer(LEFT_CURVES);
        for (int i = MagicNumberConstant.ZERO; i < list.size(); i = MathUtil.safeAddOne(i)) {
            stringBuffer.append(list.get(i).getValues());
            if (i < MathUtil.safeSubtractOne(list.size())) {
                stringBuffer.append(StringUtils.SPACE);
                stringBuffer.append(COMMA);
                stringBuffer.append(StringUtils.SPACE);
            }
        }
        stringBuffer.append(RIGHT_CURVES);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(LOG_DATE_FORMAT);
        LogUtil.i(tag,
                StringUtils.SPACE,
                list.get(MagicNumberConstant.ZERO).getClassName(),
                StringUtils.SPACE,
                list.get(MagicNumberConstant.ZERO).getMethodName(),
                StringUtils.SPACE,
                stringBuffer.toString(),
                StringUtils.SPACE,
                TIME_STRING, simpleDateFormat.format(new Date()));
    }

    /**
     * Print Response Result
     * @param tag
     * @param result
     */
    public static void printResponseResult(String tag, Object result) {
        StringBuffer stringBuffer = new StringBuffer(LEFT_CURVES);
        stringBuffer.append(result);
        stringBuffer.append(RIGHT_CURVES);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(LOG_DATE_FORMAT);
        LogUtil.i(tag,
                StringUtils.SPACE,
                stringBuffer.toString(),
                StringUtils.SPACE,
                TIME_STRING, simpleDateFormat.format(new Date()));
    }

    /**
     * Gets instance.
     *
     * @return the instance
     */
    public static LogQueue getInstance() {
        if (null == sLogQueue) {
            synchronized (LogQueue.class) {
                if (null == sLogQueue) {
                    sLogQueue = new LogQueue();
                }
            }
        }
        return sLogQueue;
    }

    /**
     * Put.
     *
     * @param logBean the log bean
     */
    public void put(LogBean logBean) {
        try {
            mBlockingQueue.put(logBean);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {

        }
    }

    /**
     * To param value string.
     *
     * @param param the param
     * @return the string
     */
    private static String toParamValue(Object param) {
        StringBuffer sb = new StringBuffer(LEFT_BRACKETS);
        if (param instanceof List) {
            sb.append(toIteratorParamValue(((List) param).iterator()));
        } else if (param instanceof Map) {
            sb.append(toIteratorParamValue(((Map) param).entrySet().iterator()));
        } else {
            sb.append(toSerialParamValue(param));
        }
        sb.append(RIGHT_BRACKETS);
        return sb.toString();
    }

    /**
     * To iterator param value string.
     *
     * @param iterator the iterator
     * @return the string
     */
    private static String toIteratorParamValue(Iterator iterator) {
        StringBuffer sb = new StringBuffer(LEFT_BRACKETS);
        while (iterator.hasNext()) {
            Object itemObject = iterator.next();
            sb.append(toSerialParamValue(itemObject));
            if (iterator.hasNext()) {
                sb.append(StringUtils.SPACE);
                sb.append(COMMA);
                sb.append(StringUtils.SPACE);
            }
        }
        sb.append(RIGHT_BRACKETS);
        return sb.toString();
    }

    /**
     * To serial param value string.
     *
     * @param param the param
     * @return the string
     */
    private static String toSerialParamValue(Object param) {
        StringBuffer stringBuffer = new StringBuffer();
        if (param != null) {
            try {
                Method method = param.getClass().getMethod(METHOD_NAME);
                stringBuffer.append(method.invoke(param));
            } catch (NoSuchMethodException noSuchMethodException) {
                stringBuffer.append(param.toString());
            } catch (IllegalAccessException illegalAccessException) {

            } catch (InvocationTargetException invocationTargetException) {

            } finally {

            }

        }
        return stringBuffer.toString();
    }

}
